<?php

/**
 * User: day
 * Date: 2018/08/07
 * Time: 23:42
 */

namespace App\Services;


use App\Models\ActiveRecord;
use App\Models\HallPartnerConfig;
use App\Models\MoneyDeposit;
use App\Models\Order;
use App\Models\UserAuthStatus;
use common\enum\ActiveEnum;
use common\enum\CommonEnum;
use common\enum\MoneyDepositEnum;
use common\enum\MoneyLogEnum;
use common\utils\RedisKeys;
use App\Models\Active;
use App\Models\ActiveApply;
use App\Models\User;
use common\utils\SysCode;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Carbon;
use Mockery\Exception;


class ActivityService
{
    //活动申请记录状态(0:待处理, 1:通过, 2:拒绝)'
    const NO_SEND = 0;
    const IS_SEND = 1;
    const iS_CANCEL = 2;

    const CONTEST_VALITBET = 1;
    const CONTEST_WON = 2;
    const CONTEST_LOSE = 3;
    const GAME_NAME = [
        CommonEnum::GAME_EGAME => '电子',
        CommonEnum::GAME_LIVE => '视讯',
        CommonEnum::GAME_SPORT => "体育",
        CommonEnum::GAME_ESPORT => '电竞',
        CommonEnum::GAME_LOTTERY => '彩票',
        CommonEnum::GAME_CARD => '棋牌'
    ];

    /**
     * 获取满足时间的有效活动 原 list 函数
     * @param int $templateID 活动的模板ID
     * @param string $date 当前日期
     * @param int $status 活动的状态
     */
    public static function getActiveList($templateID, $hall_id)
    {
        // DB::connection()->enableQueryLog();
        $date = date('Y-m-d');
        $list = Active::where([
            'template_id' => $templateID,
            'hall_id' => $hall_id
        ])
            ->whereIn('status', [ActiveEnum::ACTIVE_STATUS_ENABLE, ActiveEnum::ACTIVE_STATUS_SENDING])
            ->whereRaw("DATE_FORMAT(begin_time,'%Y-%m-%d')<='{$date}'")
            ->get()->toArray();
        // print_r(DB::getQueryLog());
        return $list;
    }

    public static function updateActiveStatus($id, $status)
    {
        $model = Active::where(['id' => $id])->first();
        $model->status = $status;
        $model->save();
    }

    /**
     * 检测用户是否在活动截止时间前参加了活动，并且还未派奖
     * @param int $userID 用户ID
     * @param string $date 截止时间？？
     * @param int $templateID 活动模板ID
     */
    public static function checkIfPacitipate($userID, $date, $templateID, $prizeRepair)
    {
        $where = ['status' => ActiveEnum::ACTIVE_STATUS_UNSEND, 'template_id' => $templateID];
        if ($userID) {
            $where['user_id'] = $userID;
        }
        if (!$prizeRepair) {
            $where['date'] = $date;
        }
        $res = ActiveRecord::select(['id', 'hall_id', 'user_id', 'active_id', 'active_name', 'username', 'amount','status'])
            ->where($where)
            ->get()->toArray();
        return $res;
    }

    /**
     * 获取某个用户在某个活动已发放优惠的次数
     * ?? 不用加上状态判断 ??
     */
    public static function getCurSendTimes($userID, $activeID)
    {
        $times = ActiveRecord::where(['user_id' => $userID, 'active_id' => $activeID, 'status' => ActiveEnum::ACTIVE_STATUS_SEND])
            ->count();
        return $times;
    }


    /**
     * 更新参与活动的记录
     */
    public static function updateActiveRecord($id, $updateArray)
    {
        //DB::connection()->enableQueryLog();#开启执行日志
        $res = ActiveRecord::where(['id' => $id])->update($updateArray);
        //print_r(DB::getQueryLog());   //获取查询语句、参数和执行时间
        return $res;
    }

    /**
     * 增加优惠发放记录，改名，原：addApply
     */
    public static function addApply($userId, $username, $hallId, $activity, $prize)
    {
        //  计算取款要求
        $withdrawRequire = self::getWithdrawRequire($prize, $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
        $isAuto = $activity['is_auto_sendprize'] == 1;
        $model = [
            'active_id' => $activity['id'],
            'active_name' => $activity['name'],
            'coupon_amount' => $prize,
            'user_id' => $userId,
            'hall_id' => $hallId,
            'username' => $username,
            'withdraw_require' => $withdrawRequire,
            'status' => $isAuto ? ActiveEnum::ACTIVE_STATUS_SEND : ActiveEnum::ACTIVE_STATUS_UNSEND,
            'is_auto_apply' => 1
        ];

        $activeModel = new ActiveApply($model);
        $result = $activeModel->save();
        if (isset($result)) {
            Log::info("userid: " . $userId . ", name:" . $username . '申请活动奖励');
        } else {
            Log::error("派奖保存失败 ActivityService::addApply：" . $userId . ",name:" . $username . '申请活动奖励');
        }

        return isset($result);
    }

    /**
     * 判断用户是否可参加优惠 或 返水
     * @param array $user
     * @param  string $type
     * @return bool
     */
    public static function checkUserAuth($userId, string $type)
    {
        $auth = UserAuthStatus::where(['user_id' => $userId, $type => 1])->get()->toArray();
        if (!$auth) {
            return true;
        }
        return false;
    }

    // ======================================================== 每日投注活动相关 ============================================================
    /*
     * 每日投注 记录每日投注用户
     */
    public static function pushPlayerInfo($activity, $hall_id, $start, $end)
    {
        $ruleArr = $activity['rule'];//优惠规则
        $orderdata = $orders = [];
        $orderdata = self::getOrders($activity, $hall_id, $start, $end);
        $orders = self::getFilterDataByLevel($orderdata, $activity);
        if (!$orders) {
            return;
        }
        $playerInfo = [];
        foreach ($orders as $order) {
            $res = $playerInfo[$order['user_id']] ?? [
                'reckon_time' => '',
                'user_id' => '',
                'username' => '',
                'game_type' => '',
                'validbet' => 0,
                'profit' => 0
            ];
            $res['reckon_time'] = $order['reckon_time'];
            $res['user_id'] = $order['user_id'];
            $res['username'] = $order['username'];
            $res['game_type'] = $order['game_type'];
            $res['validbet'] += $order['validbet'];
            $res['profit'] += $order['profit'];
            $playerInfo[$order['user_id']] = $res;
        }
        $redis = Redis::connection();
        foreach ($playerInfo as $player) {
            if ($player['validbet'] < $ruleArr['rule']['bet_money']) {
                continue;
            }
            $key = RedisKeys::ACTIVITY_DAILYBET_TIMES .$activity['id'].'_'.$player['user_id'];
            if ($redis->exists($key)) {
                $betdatas_json = $redis->get ($key);
                $betdatas = json_decode ($betdatas_json,true);
                $lastdate = Carbon::parse($betdatas['lastday'])->addDay (1)->toDateString();
                $nowdate = Carbon::parse($start)->toDateString();
                if ($lastdate == $nowdate){
                    $dailydata = [
                        'lastday' => $nowdate,
                        'num' => $betdatas['num'] + 1
                    ];
                }else{
                    $dailydata = [
                        'lastday' => $nowdate,
                        'num' => 1
                    ];
                }

            }else{
                $dailydata = [
                    'lastday' => Carbon::parse($start)->toDateString(),
                    'num' => 1
                ];
            }
            $redis->set ($key,json_encode ($dailydata));
        }
    }

    /*
     * 每日投注 添加每日投注数据
     */
    public static function addDailyBetData($activity, $hall_id, $start, $end)
    {
        $ruleArr = $activity['rule'];//优惠规则
        $redis = Redis::connection();
        $keys = $redis->keys(RedisKeys::ACTIVITY_DAILYBET_TIMES .$activity['id'].'_'. "*");
        // 奖励金额
        $prizeAmount = $ruleArr['rule']['prize'];
        //计算提款条件
        $withdraw_require = self::getWithdrawRequire($prizeAmount, $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
        foreach ($keys as $key) {
            $betdatas_json = $redis->get($key);
            $betdatas_arr = json_decode ($betdatas_json,true);
            if ($betdatas_arr['num'] >= $ruleArr['rule']['continued_days']) {
                $userid = substr($key,strrpos($key,'_')+1);
                $user = UserService::getUserBaseInfo($userid);
                $model['amount'] = $prizeAmount;
                $model['active_id'] = $activity['id'];
                $model['active_name'] = $activity['name'];
                $model['hall_id'] = $activity['hall_id'];
                $model['user_id'] = $userid;
                $model['username'] = $user['username'];
                $model['status'] = ActiveEnum::ACTIVE_STATUS_UNSEND;
                $model['template_id'] = ActiveEnum::ACTIVE_EVERY_DAY_BET;
                $model['date'] = Carbon::parse($start)->toDateString();
                $detail = array_merge($user, $activity);
                $model['detail'] = json_encode($detail);
                $model['withdraw_require'] = $withdraw_require;
                if ($activity['is_auto_sendprize']) {
                    $res = DB::table('active_record')->insert($model);
                } else {
                    $res = self::addApply($userid,$user['username'],$hall_id, $activity, $prizeAmount);
                }
                if ($res) {
                    $redis->del($key);
                } else {
                    Log::error("保存数据出错：ActivityService::addDailyBetData, " . $res);
                }
            }
        }
    }
    // ======================================================== 每日投注活动相关结束 ============================================================

    /**
     * 计算打码量要求
     * @param int $prizeAmount  优惠金额
     * @param int $withdrawRequireType 打码量类型
     * @param int $withdrawRequireTimes 倍数
     * @param int $withdrawRequireValidbet 固定金额
     * @return float|int
     */
    public static function getWithdrawRequire($prizeAmount, $withdrawRequireType, $withdrawRequireTimes, $withdrawRequireValidbet)
    {
        if ($withdrawRequireType == ActiveEnum::ACTIVE_WITHDRAW_TYPE_TIMES) {//打码倍数
            $withdraw_require = $prizeAmount * $withdrawRequireTimes / CommonEnum::PERCENT_TIMES;
        } else if ($withdrawRequireType == ActiveEnum::ACTIVE_WITHDRAW_TYPE_AMOUNT) {//固定打码
            $withdraw_require = $withdrawRequireValidbet;
        } else {//没得取款要求
            $withdraw_require = 0;
        }
        return $withdraw_require;
    }
    // ======================================================== 连续闯关活动相关 ============================================================
    /**
     *连续闯关  获取用户连赢数据
     */
    public static function addBreaking($activity, $hall_id, $start, $end)
    {
        $ruleArr = $activity['rule'];//优惠规则
        $games = $ruleArr['game'];
        foreach ($ruleArr['rule']['prize'] as $key => $rule) {
            $times[$key] = $rule['times'];
        }
        array_multisort($times, SORT_DESC, $ruleArr['rule']['prize']);

        $orderdata = $orders = [];
        $orderdata = self::getOrders($activity,$hall_id,$start,$end);
        $orders = self::getFilterDataByLevel($orderdata,$activity);
        if (!$orders) {
            return;
        }
        $num = 0;
        $winnum = [];
        foreach ($orders as $k => $ord) {
            if ($ord['validbet'] < $ruleArr['rule']['bet_money']) {
                continue;
            }
            $res = $winnum[$ord['user_id']] ?? [
                    $winnum[$ord['user_id']]['user_id'] = $ord['user_id'],
                    $winnum[$ord['user_id']]['num'] = 0,
                    $winnum[$ord['user_id']]['username'] = $ord['username']
                ];
            if ($ord['profit'] <= 0 || $ord['validbet'] < $ruleArr['rule']['bet_money']) {
                if ($winnum[$ord['user_id']]['num'] != 0) {
                    $winnum[$ord['user_id']]['num'] = $num;
                    $num = 0;
                }
                continue;
            }
            $num++;
            $winnum[$ord['user_id']]['num'] = $num;
        }
        foreach ($winnum as $id => $user) {
            $numarr[$id] = $user['num'];
        }
        array_multisort($numarr, SORT_DESC, $winnum);
        foreach ($ruleArr['rule']['prize'] as $key => $rule) {
            foreach ($winnum as $id => $maxnum) {
                if ($maxnum['num'] >= $rule['times']) {
                    $model['amount'] = $rule['money'];
                    $model['active_id'] = $activity['id'];
                    $model['active_name'] = $activity['name'];
                    $model['user_id'] = $maxnum['user_id'];
                    $model['hall_id'] = $activity['hall_id'];
                    $model['username'] = $maxnum['username'];
                    $model['status'] = ActiveEnum::ACTIVE_STATUS_UNSEND;
                    $model['template_id'] = ActiveEnum::ACTIVE_CONTINUOUS_PASS;
                    $model['date'] = Carbon::parse($start)->toDateString();
                    $detail = array_merge($maxnum, $activity);
                    $model['detail'] = json_encode($detail);
                    $model['withdraw_require'] = self::getWithdrawRequire($rule['money'], $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
                    if ($activity['is_auto_sendprize']) {
                        $res = DB::table('active_record')->insert($model);
                    } else {
                        $res = self::addApply($maxnum['user_id'],$maxnum['username'],$hall_id,$activity, $rule['money']);
                    }
                    if (!$res) {
                        Log::error("连续闯关 保存数据出错：" . $res);
                    }
                    unset($winnum[$id]);
                    break;
                }
            }

        }


    }
    // ======================================================== 连续闯关活动相关结束 ============================================================

    // ======================================================== 擂台奖活动相关 ============================================================
    /**
     * 擂台奖   添加擂台奖用户数据
     */
    public static function addContest($activity, $hall_id, $start, $end)
    {
        $ruleArr = $activity['rule'];//优惠规则
        $orders = self::getOrders($activity, $hall_id, $start, $end);
        $orders = self::getFilterDataByLevel($orders,$activity);
        if (!$orders) {
            return;
        }
        $sum_orders = [];
        foreach ($orders as $order) {
            $res = $sum_orders[$order['user_id']] ?? [
                'reckon_time' => '',
                'user_id' => '',
                'username' => '',
                'game_type' => '',
                'validbet' => 0,
                'profit' => 0
            ];
            $res['reckon_time'] = $order['reckon_time'];
            $res['user_id'] = $order['user_id'];
            $res['username'] = $order['username'];
            $res['game_type'] = $order['game_type'];
            $res['validbet'] += $order['validbet'];
            $res['profit'] += $order['profit'];
            $sum_orders[$order['user_id']] = $res;
        }
        switch ($ruleArr['rule']['type']) {
            case self::CONTEST_VALITBET:
                foreach ($sum_orders as $key => $info) {
                    $betmoney[$key] = $info['validbet'];
                }
                array_multisort($betmoney, SORT_DESC, $sum_orders);
                break;
            case self::CONTEST_WON:
                foreach ($sum_orders as $key => $info) {
                    $loseearn[$key] = $info['profit'];
                }
                array_multisort($loseearn, SORT_DESC, $sum_orders);
                foreach ($sum_orders as $k => $v) {
                    if ($v['profit'] <= 0) {
                        unset($sum_orders[$k]);
                    }
                }
                break;
            case self::CONTEST_LOSE:
                foreach ($sum_orders as $key => $info) {
                    $loseearn[$key] = $info['profit'];
                }
                array_multisort($loseearn, SORT_ASC, $sum_orders);
                foreach ($sum_orders as $k => $v) {
                    if ($v['profit'] >= 0) {
                        unset($sum_orders[$k]);
                    }
                }
                break;
        }
        foreach ($ruleArr['rule']['prize'] as $key => $prize) {
            if (!isset($sum_orders[$key])) break;
            $model['amount'] = $prize;
            $model['active_id'] = $activity['id'];
            $model['active_name'] = $activity['name'];
            $model['user_id'] = $sum_orders[$key]['user_id'];
            $model['username'] = $sum_orders[$key]['username'];
            $model['hall_id'] = $activity['hall_id'];
            $model['status'] = ActiveEnum::ACTIVE_STATUS_UNSEND;
            $model['template_id'] = ActiveEnum::ACTIVE_PLATFORM_PRIZE;
            $model['date'] = Carbon::parse($start)->toDateString();
            $model['detail'] = json_encode($sum_orders[$key]);
            $model['withdraw_require'] = self::getWithdrawRequire($prize, $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
            if ($activity['is_auto_sendprize']) {
                $res = DB::table('active_record')->insert($model);
            } else {
                $res = self::addApply($sum_orders[$key]['user_id'],$sum_orders[$key]['username'],$hall_id, $activity, $prize);
            }
            if (!$res) {
                Log::error("擂台奖 保存数据出错：" . $res);
            }
        }
    }
    // ======================================================== 擂台奖活动相关结束 ============================================================

    // ======================================================== 加奖活动相关 ============================================================
    /**
     * 加奖 添加加奖数据
     */
    public static function addBonus($activity, $hall_id, $start, $end)
    {
        $ruleArr = $activity['rule'];//优惠规则
        foreach ($ruleArr['rule'] as $key => $rule) {
            $money[$key] = $rule['money'];
        }
        array_multisort($money, SORT_DESC, $ruleArr['rule']);
        $orders = self::getOrders($activity, $hall_id, $start, $end);
        if (!$orders) {
            return;
        }
        $orders = self::getFilterDataByLevel($orders,$activity);
        foreach ($orders as $i=>$ord) {
            if ($ord['profit'] <= 0) {
                continue;
            }
            foreach ($ruleArr['rule'] as $key => $rule) {
                if (($ord['profit'] + $ord['validbet']) >= $rule['money']) {
                    if ($rule['type'] == "1") {
                        $model['amount'] = $rule['prize'];
                    } elseif ($rule['type'] == "2") {
                        $model['amount'] = ($ord['profit'] + $ord['validbet']) * $rule['percent'] / CommonEnum::PERCENT_TIMES / CommonEnum::PERCENT_TIMES;
                        isset($rule['upper_limit']) && $rule['upper_limit'] > 0 && $model['amount'] > $rule['upper_limit'] && $model['amount'] = $rule['upper_limit'];
                    }
                    $model['active_id'] = $activity['id'];
                    $model['active_name'] = $activity['name'];
                    $model['hall_id'] = $activity['hall_id'];
                    $model['user_id'] = $ord['user_id'];
                    $model['username'] = $ord['username'];
                    $model['status'] = ActiveEnum::ACTIVE_STATUS_UNSEND;
                    $model['template_id'] = ActiveEnum::ACTIVE_PRIZE_ON_PRIZE;
                    $model['date'] = Carbon::parse($start)->toDateString();
                    $detail = array_merge($ord, $activity);
                    $model['detail'] = json_encode($detail);
                    $model['withdraw_require'] = self::getWithdrawRequire($model['amount'], $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
                    if ($activity['is_auto_sendprize']) {
                        $res = DB::table('active_record')->insert($model);
                    } else {
                        $res = self::addApply($ord['user_id'],$ord['username'],$hall_id,$activity,$model['amount']);
                    }
                    if (!$res) {
                        Log::error("加奖 保存数据出错：" . $res);
                    }
                   unset($orders[$i]);
                   break;
                }
            }
        }

    }
// ======================================================== 加奖活动相关结束 ============================================================

// ======================================================== 每日首充活动开始 ============================================================
    /**
     * 每日首充添加每日首充数据
     * 如开始时间不是日期起始时间，如：开始时间是10:00:00 那么10点前的首充会员都不会算首充优惠
     * @param array $activity 活动信息
     * @param int $hallId 厅id
     * @param string $startTime 统计数据开始时间
     * @param string $endTime 统计数据结束时间
     */
    public static function addDailyDepositData($activity, $hallId, $startTime, $endTime)
    {
        if (!$activity){
            return ;
        }
        //优惠规则
        if(empty($activity['rule'])){
            return;
        }
        $activeId = $activity['id'];
        $depositAmount = $activity['rule']['rule']['deposit_amount'];
        $continuedDays = $activity['rule']['rule']['continued_days'];

        $expUserId = [];
        // 如果起始时间不在日期起始，需要过滤充值时间在0点到这个时间的会员
        $dayStart = date('Y-m-d 00:00:00', strtotime($startTime));
        if($startTime>=$dayStart){
            $expUserList = MoneyDeposit::select([
                'id',
                'hall_id',
                'user_id',
                'name as username',
                'amount',
                'order_number',
                'is_online',
                'offline_pay_type',
                'online_pay_id',
                'recharge_time',
                'created_at',
                DB::raw("left(recharge_time, 10) as date"),
            ])->where(['hall_id'=>$hallId, 'status'=>MoneyDepositEnum::STATUS_PAID])->where(function($q){
                $q->orwhere('is_online','=',MoneyDepositEnum::IS_ONLINE_TRUE)
                    ->orwhere('offline_pay_type', '<=', MoneyDepositEnum::DEPOSIT_TYPE_CYBER_BANK);
            })->where('recharge_time', '>=', $dayStart)
                ->where('recharge_time', '<', $startTime)
                ->orderby('recharge_time','asc')
                ->get()->toArray();
            $expUserId = array_unique(array_column($expUserList, 'user_id'));
        }

        // 获取充值数据（线上、线下）
        $query = MoneyDeposit::select([
            'id',
            'hall_id',
            'user_id',
            'name as username',
            'amount',
            'order_number',
            'is_online',
            'offline_pay_type',
            'online_pay_id',
            'recharge_time',
            'created_at',
            DB::raw("left(recharge_time, 10) as date"),
        ])->where(['hall_id'=>$hallId, 'status'=>MoneyDepositEnum::STATUS_PAID])->where(function($q){
            $q->orwhere('is_online','=',MoneyDepositEnum::IS_ONLINE_TRUE)
                ->orwhere('offline_pay_type', '<=', MoneyDepositEnum::DEPOSIT_TYPE_CYBER_BANK);
        })->where('recharge_time', '>=', $startTime)
            ->where('recharge_time', '<=', $endTime);
        if(!empty($expUserId)){
            $query->whereIn('user_id',$expUserId);
        }
        $allUserData = $query->orderby('recharge_time','asc')
            ->get()->toArray();
        if(empty($allUserData)){
            return ;
        }
        // 层级过滤, 禁止优惠状态过滤
        $allUserData = self::getFilterDataByLevel($allUserData,$activity);

        $allUserId = array_unique(array_column($allUserData, 'user_id'));

        // 过滤限制数据和重复数据
        $secondUserId = [];//第二次及以上会员id
        $expUserId = [];
        foreach ($allUserData as $k => $user){
            // 过滤不需要的数据
            if(!in_array($user['user_id'], $allUserId)){
                unset($allUserData[$k]);
                continue;
            }
            // 过滤第二次存款数据
            if(in_array($user['user_id'], $secondUserId)){
                unset($allUserData[$k]);
                continue;
            }
            $secondUserId[] = $user['user_id'];
            // 过滤每日首充金额不符合的数据
            if($user['amount']<$depositAmount){
                unset($allUserData[$k]);
                $expUserId[] = $user['user_id'];
            }
            if(in_array($user['user_id'], $expUserId)){
                unset($allUserData[$k]);
                continue;
            }
        }
        // 数据存到redis 便于后面判断是否达到条件
        $redis = Redis::connection();
        $userInfo = [];// 会员信息数组
        foreach ($allUserData as $user){
            if ($user['amount'] < $depositAmount) {
                continue;
            }
            $key = RedisKeys::ACTIVITY_DAILY_FIRST_DEPOSIT . $hallId . ':' .$activeId . ':' . $user['user_id'];
            $cacheDate = $redis->get($key);
            $dateStr = Carbon::parse($startTime)->toDateString();
            // 存在数据
            if ($cacheDate) {
                $cacheDate = json_decode($cacheDate, true);
                // 时间不是连续时间重置为1
                if($cacheDate['lastday']!=Carbon::parse($startTime)->subDay(1)->toDateString()){
                    $cacheDate['lastday'] = $dateStr;
                    $cacheDate['num'] = 1;
                }else{
                    // 连续时间数量加1
                    $cacheDate['lastday'] = $dateStr;
                    $cacheDate['num']++;
                }
            } else {
                // 不存在数据，设置新数据
                $cacheDate = [
                    'lastday'=> $dateStr,
                    'num'=> 1,
                ];
            }
            $redis->set($key, json_encode($cacheDate));
            $userInfo['user_'.$user['user_id']] = $user['user'];
        }
        $keys = $redis->keys(RedisKeys::ACTIVITY_DAILY_FIRST_DEPOSIT . $hallId . ':' .$activeId . ':'. "*");
        $pattern = '/\d+$/';
        $recodes = [];
        $apply = [];
        foreach ($keys as $key) {
            $cacheDate = $redis->get($key);
            $cacheDate = json_decode($cacheDate, true);
            if ($cacheDate['num'] >= $continuedDays) {
                preg_match($pattern, $key, $matches);
                $userId = $matches[0];
                // 先上面数组拿会员数据，没有再取
                $prize = $activity['rule']['rule']['prize'];
                $user = empty($userInfo['user_'.$userId])? UserService::getUserBaseInfo($userId) : $userInfo['user_'.$userId];
                if ($activity['is_auto_sendprize']) {
                    $model['amount'] = $prize;
                    $model['active_id'] = $activeId;
                    $model['active_name'] = $activity['name'];
                    $model['hall_id'] = $hallId;
                    $model['user_id'] = $userId;
                    $model['username'] = $user['username'];
                    $model['status'] = 0;
                    $model['template_id'] = ActiveEnum::ACTIVE_EVERY_DAY_BET;
                    $model['date'] = $cacheDate['lastday'];
                    $detail = array_merge($user, [
                        'active_id'=>$activeId,
                        'active_name'=>$activity['name'],
                        'active_title'=>$activity['title'],
                        'begin_time'=>$activity['begin_time'],
                        'end_time'=>$activity['end_time'],
                        'rule'=>$activity['rule'],
                    ]);
                    $model['detail'] = json_encode($detail);
                    $model['withdraw_require'] = self::getWithdrawRequire($model['amount'], $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
                    $recodes[] = $model;
                } else {
                    $withdrawRequire = self::getWithdrawRequire($prize, $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
                    $isAuto = $activity['is_auto_sendprize'] == 1;
                    $model = [
                        'active_id' => $activeId,
                        'active_name' => $activity['name'],
                        'coupon_amount' => $prize,
                        'user_id' => $userId,
                        'hall_id' => $hallId,
                        'username' => $user['username'],
                        'withdraw_require' => $withdrawRequire,
                        'status' => $isAuto ? ActiveEnum::ACTIVE_STATUS_SEND : ActiveEnum::ACTIVE_STATUS_UNSEND,
                        'is_auto_apply' => 1
                    ];
                    $apply[] = $model;
                }
                if(count($recodes)>10000 || count($apply)>10000){
                    static::saveDateAndDelRedisDate($activeId, $activity['name'], $recodes, $apply);
                    $recodes = $apply = [];
                }
            }
        }
    }
// ======================================================== 每日首充活动结束 ============================================================
// ======================================================== 注册送活动开始 ============================================================
    /**
     * 添加注册送数据
     * 注册送模版类型的只能发一次
     * @param array $activity 活动信息
     * @param int $hallId 厅id
     * @param string $startTime 统计数据开始时间
     * @param string $endTime 统计数据结束时间
     * @param int $isRepair 是否修补 0 默认值 不是
     */
    public static function addRegisterPrizeData($activity,$hallId,$startTime,$endTime, $isRepair=0)
    {
        if (!$activity){
            return ;
        }
        $today = date("Y-m-d H:i:s");
        // 注册送是实时活动停用期间则不送 并且是非修复数据
        if ($activity['status']==ActiveEnum::ACTIVE_STATUS_UNENABLE && $isRepair){
            return;
        }
        //优惠规则
        if(empty($activity['rule'])){
            return;
        }
        $activeId = $activity['id'];
        // 获取数据
        $count = User::where(['hall_id'=>$hallId])->where('created_at', '>=', $startTime)->where('created_at', '<=', $endTime)->count();
        if(empty($count)){
            return;
        }
        // 计算奖金和打码量
        $prize = $activity['rule']['rule']['prize'];
        $withdrawRequire = self::getWithdrawRequire($prize, $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
        // 会员派奖数组定义
        $recodes = $apply = [];
        // 定义分页大小
        $size = 1000;
        for($i=1;$i<=ceil($count/$size);$i++){
            $users = User::select(['id','username','created_at'])->where(['hall_id'=>$hallId])->where('created_at', '>=', $startTime)->where('created_at', '<=', $endTime)
                ->offset(($i - 1) * $size)
                ->limit($size)->get()->toArray();
            $userIds = array_column($users, 'id');
            $expUserIds = [];
            // 手动派发的人
            $manualSendUserList = ActiveApply::where([
                'a.hall_id' => $hallId,
                'active.hall_id' => $hallId,
                'active.template_id' => ActiveEnum::ACTIVE_REGISTERED_OFFER
            ])->from("active_apply as a")->leftJoin("active", "a.active_id","=","active.id")
                ->where('a.created_at', '<=', $today)->wherein('a.user_id',  $userIds)->get()->toArray();
            $manualSendUser = array_column($manualSendUserList, 'user_id');
            $expUserIds = array_merge($manualSendUser, $expUserIds);
            // 自动派发的人
            $autoSendUserList = ActiveRecord::where([
                'hall_id' => $hallId,
                'template_id' => ActiveEnum::ACTIVE_REGISTERED_OFFER
            ])->wherein('user_id',  $userIds)->get()->toArray();
            $autoUser = array_column($autoSendUserList, 'user_id');
            $expUserIds = array_merge($autoUser, $expUserIds);
            $expUserIds = array_unique($expUserIds);

            // 获取可以发放的列表
            $canSendUserIds = array_diff($userIds, $expUserIds);

            // 组装数据
            foreach ($users as $user){
                if(!in_array($user['id'], $canSendUserIds)){
                    continue;
                }
                // 自动派发
                if ($activity['is_auto_sendprize']) {
                    $model['amount'] = $prize;
                    $model['active_id'] = $activeId;
                    $model['active_name'] = $activity['name'];
                    $model['hall_id'] = $hallId;
                    $model['user_id'] = $user['id'];
                    $model['username'] = $user['username'];
                    $model['status'] = ActiveEnum::ACTIVE_STATUS_UNSEND;// 待处理
                    $model['template_id'] = ActiveEnum::ACTIVE_REGISTERED_OFFER;// 模版id是注册送
                    $model['date'] = date('Y-m-d', strtotime($user['created_at']));
                    $detail = array_merge($user, [
                        'active_id'=>$activeId,
                        'active_name'=>$activity['name'],
                        'active_title'=>$activity['title'],
                        'begin_time'=>$activity['begin_time'],
                        'end_time'=>$activity['end_time'],
                        'rule'=>$activity['rule'],
                    ]);
                    $model['detail'] = json_encode($detail);
                    $model['withdraw_require'] = $withdrawRequire;
                    $recodes[] = $model;
                } else {
                    // 手动派发
                    $isAuto = $activity['is_auto_sendprize'] == 1;
                    $model = [
                        'active_id' => $activeId,
                        'active_name' => $activity['name'],
                        'coupon_amount' => $prize,
                        'user_id' => $user['id'],
                        'hall_id' => $hallId,
                        'username' => $user['username'],
                        'withdraw_require' => $withdrawRequire,
                        'status' => $isAuto ? ActiveEnum::ACTIVE_STATUS_SEND : ActiveEnum::ACTIVE_STATUS_UNSEND,
                        'is_auto_apply' => 1
                    ];
                    $apply[] = $model;
                }
                if(count($recodes)>10000 || count($apply)>10000){
                    static::saveDateAndDelRedisDate($activeId, $activity['name'], $recodes, $apply);
                    $recodes = $apply = [];
                }
            }
        }
    }
// ======================================================== 注册送活动结束 ============================================================

    /**
     * 回水统计详情活动
     */
    public static function addRebetData($activity, $hall_id, $startTime, $endTime)
    {
        $ruleArr = $activity['rule'];//优惠规则
        $rules = $ruleArr['rule'];
        $games = $ruleArr['game']??[];
        array_multisort(array_column($rules, "money"), SORT_ASC, $rules);//讲规则按照累计输钱由小到大排序
        $orders = self::getOrders($activity,$hall_id,$startTime,$endTime);
        if (!$orders) {
            return false;
        }
        $orders = self::getFilterDataByLevel($orders,$activity);//排除不符合用户等级的部分
        if(empty($orders)){
            return false;
        }
        $orderData = static::foramtDataGames($orders, $games);//格式化注单数据
        static::handleData($orderData, $activity, $rules,$startTime,$endTime);
    }

    /**
     * 处理数据
     * @param array $data
     * @param array $activity
     * @param array $rules
     * @param array $userData
     * @param array $times
     */

    public static function handleData(array $data, array $activity, array $rules,$startTime,$endTime)
    {
        $apply = [];//手动发放记录
        $records = [];//延迟发放记录
        foreach ($data as $value) {
            $level = static::getPrizeLevel($value['profit'], $rules);
            if (empty($level)) {//不符合条件不发
                continue;
            }
            if ($level['type'] ==ActiveEnum::ACTIVE_PRIZE) {//固定金额
                $deposit_amount = intval($level['prize']);
            } else {//比例
                $deposit_amount = intval(abs($value['profit'] * $level['percent'] / CommonEnum::PERCENT_TIMES / CommonEnum::PERCENT_TIMES));//现在活动比例都是x100保存的
                if (isset($level['upper_limit']) && $level['upper_limit'] > 0) {//最大值
                    $deposit_amount = $deposit_amount < intval($level['upper_limit']) ? $deposit_amount : intval($level['upper_limit']);
                }
            }
            //计算提款条件
            $withdraw_require = self::getWithdrawRequire($deposit_amount, $activity['withdraw_require_type'], $activity['withdraw_require_times'], $activity['withdraw_require_validbet']);
            if ($activity['is_auto_sendprize']) {//自动发放
                $detail['user_id'] = intval($value['user_id']);
                $detail['username'] = $value['username'];
                $detail['amount'] = $deposit_amount;
                $detail['profit'] = $value['profit'];
                $detail['rule'] = $level;
                $detail['games'] = $value['games'];//本次统计活动数据
                $detail['rules'] = $activity['rule'];
                $detail['withdraw_require'] = $withdraw_require;
                $detail['startTime'] = $startTime;
                $detail['endTime'] = $endTime;

                $insert['hall_id'] = $activity['hall_id'];
                $insert['user_id'] = $value['user_id'];
                $insert['username'] = $value['username'];
                $insert['template_id'] = ActiveEnum::ACTIVE_RESCUE_PRIZE;
                $insert['date'] = Carbon::parse($startTime)->toDateString();
                $insert['amount'] = $deposit_amount;
                $insert['active_id'] = intval($activity['id']);
                $insert['detail'] = json_encode($detail, 320);
                $insert['withdraw_require'] = $withdraw_require;
                $insert['active_name']=$activity['name'];
                $insert['status'] = self::NO_SEND;
                $records[] = $insert;
            } else {//手动发放的  插入到active_apply表
                $apply[] = [
                    'hall_id' => intval($activity['hall_id']),
                    'user_id' => intval($value['user_id']),
                    'username' => $value['username'],
                    'active_id' => intval($activity['id']),
                    'active_name' => $activity['name'],
                    'coupon_amount' => $deposit_amount,
                    'withdraw_require' => $withdraw_require,
                    'is_auto_apply' => 1,
                    'status' => self::NO_SEND
                ];
            }
        }
        if (!empty($apply)) {
            $applys=array_chunk($apply,1000);
            foreach ($applys as $value){
                $status = DB::table('active_apply')->insert($value);
                if (!$status || $status === false) {
                    Log::error("回水活动保存手动发放优惠申请失败");
                }
            }
        }
        if (!empty($records)) {
            $records=array_chunk($records,1000);
            foreach ($records as $value){
                $status = DB::table('active_record')->insert($value);
                if (!$status || $status === false) {
                    Log::error("回水活动保存自动延迟优惠申请失败");
                }
            }
        }
    }

    public static function isAutoSend(array $data) : bool
    {
        $status = DB::table('active_record')->insertGetId($data);
        if (!$status || $status === false) {
            return false;
        }
        //新增入款表
        $datalog['user_id'] = $data['user_id'];
        $datalog['amount'] = 0;
        $datalog['coupon_amount'] = $data['amount'];
        $datalog['hall_id'] = $data['hall_id'];
        $datalog['username'] = $data['user_name'];
        $datalog['order_number'] = generate_order_number();
        $datalog['category'] = MoneyLogEnum::CATEGORY_IN;
        $datalog['type'] = MoneyLogEnum::USER_DEPOSIT_REBET;
        $datalog['remark'] = "回水活动发放救援金,活动id为" . $data['active_id'];
        // $status = MoneyService::updateMoney($datalog, 1);
        MoneyService::updateMoney($data['hall_id'], $data['user_id'], $data['username'], 
            0, MoneyLogEnum::USER_MONEY_INCOME, MoneyLogEnum::USER_DEPOSIT_REBET, 0, $data['amount'], 
            0, 0, "回水活动发放救援金,活动id为" . $data['active_id']);
        return $status;
    }


    /**
     * 格式化注单信息
     * @param array $data
     * @return array
     */
    public static function foramtDataGames(array $data, array $games) : array
    {
        $result = [];
        $userIds = array_unique(array_column($data, "user_id"));
        foreach ($userIds as $value) {
            if (!isset($result[$value])) {
                $result[$value] = [
                    'user_id' => $value,
                    'profit' => 0,
                    'games' => []
                ];
            }
            foreach ($games as $val) {
                $key = "{$val['game_id']}_{$val['game_type']}";
                $result[$value]['games'][$key] = ['game_id' => $val['game_id'], 'game_type' => $val['game_type'], 'profit' => 0, 'game_name' => static::getGameName($val['game_id'], $val['game_type'])];
            }
        }

        foreach ($data as $value) {
            $gameId = $value['partner_id'];
            $userId = $value['user_id'];
            $gameType = $value['game_type'];
            $key = $gameId . "_" . $gameType;
            $result[$userId]['games'][$key]['profit'] += $value['profit'];
            $result[$userId]['profit'] += $value['profit'];
            $result[$userId]['username'] = $value['username'];
        }
        foreach ($result as $key =>$value) {
            if($result[$key]['profit'] >=0 ){//此处直接干掉赢钱的，赢钱是没有优惠的
                unset($result[$key]);
                continue;
            }
            $result[$key]['games'] = array_values($result[$key]['games']);
        }
        return $result;
    }

    /**
     * 获取partner 数据
     * @return array
     */
    public static function getPartner() : array
    {
        $data = HallPartnerConfig::select("partner_id", 'game_type', 'partner_name')->get()->toArray();
        $result = [];
        foreach ($data as $value) {
            $result[] = ['game_id' => $value['partner_id'], 'game_type' => $value['game_type'], 'game_name' => $value['partner_name']];
        }
        return $result;
    }

    /**
     * 获取游戏name
     * @param int $gameId
     * @param int $gameType
     * @return string
     */
    public static function getGameName(int $gameId, int $gameType) : string
    {
        $game = static::getPartner();
        foreach ($game as $value) {
            if ($gameId == $value['game_id'] && $gameType == $value['game_type']) {
                return $value['game_name'] . self::GAME_NAME[$value['game_type']];
            }
        }
        return "";
    }



    /**
     * 过滤达到次数限制和禁止优惠的会员id
     * @param array $userIds
     * @param array $activity
     * @return array
     */
    public static function getMatchLimitsUser(array $userIds, array $activity, int $hall_id) : array
    {
        if (!$activity['limit_times'] || empty($activity['limit_times'])) {//没有领取次数限制
            return $userIds;
        }
        $userList = ActiveRecord::where('active_id', intval($activity['id']))->whereIn('user_id', $userIds)->where('status', self::IS_SEND)->where("hall_id", $hall_id)
            ->selectRaw("user_id,count(*) as count")->groupBy('user_id')->having('count', ">=", intval($activity['limit_times']))->get()->toArray();//找到数量大于限制次数的
        if (!empty($userList)) {//排除领取次数的
            $userIds = array_diff($userIds, array_column($userList, 'user_id'));
        }
        if(empty($userIds)){
            return [];
        }

        // 查询是被禁用优惠的会员
        $userAuthList = UserAuthStatus::where('is_refuse_coupon', CommonEnum::ENABLED)->whereIn('user_id', $userIds)->get()->toArray();
        if (empty($userAuthList)) {
            return $userIds;
        }
        return array_diff($userIds, array_column($userAuthList, 'user_id'));
    }

    /**
     * 根据累计输赢获取对应的奖励等级
     * @param int $total
     * @param array $rules
     * @return array
     */
    public static function getPrizeLevel(int $total, array $rules) : array
    {
        $total>=0?:$total=-$total;
        $index = "";
        foreach ($rules as $key => $value) {
            if ($value['money'] > $total) {
                continue;
            }
            $index = $key;
        }
        return $index === "" ? [] : $rules[$index];
    }

    /**
     * 筛选出符合活动层级的用户的活动数据
     * @param array $data
     * @param string $level
     * @return mixed
     */
    public static function getFilterDataByLevel($data,$activity)
    {
        $level=$activity['user_levels'];
        $user_id_arr = array_unique (array_column ($data,'user_id'));
        $userIds = array_chunk($user_id_arr,1000);
        $users = $users_arr = $user_id_arr2 = $user_info_arr = [];
        foreach ($userIds as $userId){
            $userstmp = UserService::getUsersInfo($userId);
            $users_arr = array_merge($users, $userstmp);
        }
        // 过滤层级
        foreach ($users_arr as $user) {
            if ($level) {
                $level_arr = explode(',', $level);
                if (!in_array($user['level_id'], $level_arr)) {
                    continue;
                }
            }
            $user_info_arr['user_'.$user['id']] = $user;
            $user_id_arr2[] =  $user['id'];
        }
        // 过滤超过发放次数和禁止优惠状态
        $user_id_arr2=static::getMatchLimitsUser($user_id_arr2,$activity,$activity['hall_id']);//排除领取限制的，排除禁止优惠的
        //没得符合条件的了
        if(empty($user_id_arr2)){
            return [];
        }
        foreach ($data as $k=>$v){
            if (!in_array ($v['user_id'],$user_id_arr2)){
                unset($data[$k]);
            }else{
                $data[$k]['user'] = $user_info_arr['user_'.$v['user_id']];
            }
        }
        return $data;
    }
    //从注单中查找用户
    public static function getOrders($activity, $hall_id, $start, $end)
    {
        $ruleArr = $activity['rule'];//优惠规则
        $games = $ruleArr['game']??[];
        $query = Order::select([
            'reckon_time',
            'user_id',
            'username',
            'game_type',
            'partner_id',
            'validbet',
            'profit',
            'status'
        ]);
        $query->where(['hall_id' => $hall_id]);
        if ($games) {
            foreach ($games as $game) {
                $where[] = "(partner_id = " . $game['game_id'] . " AND game_type=" . $game['game_type'] . ")";
            }
            $where_str = implode(" OR ", $where);
            $query->whereRaw("(" . $where_str . ")");

        }
        $order = $query->whereBetween('reckon_time', [$start, $end])
            ->where(['status' => CommonEnum::ORDER_STATUS_SETTLED])
            ->orderBy('reckon_time')
            ->get()->toArray();
        return $order;
    }

    /**
     * 数据持久化操作
     * @param int $activeId 活动Id
     * @param string $activeName 活动名称
     * @param array $recodes 插入active_recode数据数组
     * @param array $apply  插入active_apply数据数组
     * @param null $redis redis 连接
     * @param array $keys 需要删除的redis key
     */
    private static function saveDateAndDelRedisDate($activeId, $activeName, $recodes=[], $apply=[], $redis=null, $keys=[]){
        $tem = '活动ID:'.$activeId.' 活动名称：'.$activeName.' '.PHP_EOL;
        if(!empty($keys) || !empty($recodes) || !empty($apply)){
            try{
                DB::beginTransaction();
                if(!empty($recodes)){
                    $recode = array_chunk($recodes,500);
                    foreach ($recode as $v){
                        $res = DB::table('active_record')->insert($v);
                        if(!$res){
                            error_exit(SysCode::FAILED, $tem . json_encode($recodes) . PHP_EOL . json_encode($apply) . '插入active_record数据失败!');
                        }
                    }
                }
                if(!empty($apply)){
                    $applyList = array_chunk($apply,500);
                    foreach ($applyList as $v){
                        $res = DB::table('active_apply')->insert($v);
                        if(!$res){
                            error_exit(SysCode::FAILED, $tem.json_encode($recodes).PHP_EOL.json_encode($apply).'插入active_apply数据失败!');
                        }
                    }
                }
                if(!empty($keys)){
                    if(empty($redis)){
                        $redis = Redis::connection();
                    }
                    foreach ($keys as $key) {
                        $redis->del($key);
                    }
                }
                DB::commit();
            }catch (Exception $e){
                Log::error('插入数据失败：'.$e->getMessage());
                DB::rollBack();
            }
        }
    }
}
